Fix checklist node copying#8925
Conversation
Previously, we only manually disabled the Basis prototypes, but forgot about the Aufbau prototypes. We can completely remove the prototypes from the dev data.
✅ Feature branch deployment ready!
|
cba8d96 to
a2aa911
Compare
a2aa911 to
ef948aa
Compare
ef948aa to
c5fe5e0
Compare
…ecklist items are present in target camp
c5fe5e0 to
1643a02
Compare
There was a problem hiding this comment.
Looks good to me as soon as the runtime of the migrations in prod is checked.
One a little mean question now that the work is already done:
We have 2 cases here:
- Copy the activity in the same camp: Easy, the checklistitems are in the same camp
- Copy an activity to another camp: Hard, and a perfect solution is nearly impossible.
Maybe we could just not copy the checklistnode_checklistitem relation in this case?
(virtual 3. Copy all activities and checklists from another camp: easy)
|
|
||
| public function up(Schema $schema): void { | ||
| $this->addSql(<<<'EOF' | ||
| DELETE FROM public.checklistnode_checklistitem |
There was a problem hiding this comment.
Did you run this statement as select statement in prod?
How long did it take?
There was a problem hiding this comment.
Yes. For activities, it takes 1 s 951 ms and gives the result of 49 faulty connections. For categories, it takes 648 ms and gives the result of 0.
|
|
||
| /** @var ChecklistItem $existingParent */ | ||
| $existingParent = $existingItem->getParent(); | ||
| while (null !== $parent && null !== $existingParent && $score < 10) { |
There was a problem hiding this comment.
The 10 here is just an upper bound that the loop aborts for sure?
I think we agreed on a maximum nexting level of 3.
Maybe put it in a constant with a name?
There was a problem hiding this comment.
Ah, good point. Yes, it is a failsafe. I now extracted it into a constant in 527614e.
| $bestMatchIndex = array_find_key($matches, function ($match) use ($maxScore) { | ||
| return $match === $maxScore; | ||
| }); | ||
| if ($maxScore > 0 && null !== $bestMatchIndex) { |
There was a problem hiding this comment.
If there are only matches with score 1 (leaf has the same text),
but the parent checklistitem has another name, this will still lead to a match...
There was a problem hiding this comment.
Yes, that is intended. This algorithm is supposed to give the best match available, not find a perfect match (because the exact wording of checklist items and their parents may vary slightly over time). I also wrote tests for this: testCopyFromPrototypeAcrossCampsSearchesForItemOfSameName
| $materialNodes = array_filter($contentNodes, fn ($cn) => 'Material' == $cn['contentTypeName']); | ||
| $this->assertCount(1, $materialNodes); | ||
|
|
||
| $materialNode = reset($materialNodes); |
There was a problem hiding this comment.
why not just use $materialNodes[0] or array_first?
I tried to find the next access to $materialNodes and why you are resetting the pointer here....
There was a problem hiding this comment.
I just copied that from another test written in 9056cda and tried to be consistent. Maybe @pmattmann knows why?
@BacLuc From a user perspective, this was the behaviour before, because the relations that were copied are never visible in the UI. I ran into this problem in a real course, and initially wanted to change it so that we can copy these connections. We already do something similar with categories (although implemented in the frontend in that case) and we go to great lengths to preserve the material items in copied activities as well. When trying to implement this similar improvement for checklist items, I discovered the bug. Personally, I think with us supporting the use case of activity templates via publicly shared camps (#7481), the old behaviour is not satisfying. I know my proposed algorithm is not perfect with matching checklist items, particularly if there are some minor typo differences between the checklist items in both camps. I thought this could be a good starting point, and if we find more specific use cases, we can always improve the algorithm. However, if you insist on staying with the old behaviour, just not copying any connections, I can just drop the last two commits. My ideal vision for the copy activity feature is that activities can be copied from old courses, and they "magically" adapt to the slightly changed checklist items in the new course. I think it's fair to assume that an activity from a course will probably be copied to a similar course, which probably has similar checklists (especially with the checklist templates). I imagine (but have no hard evidence for) that this scenario is what happens most of the time, and IMO we should make it easy to work in this case. |
manuelmeister
left a comment
There was a problem hiding this comment.
Core Meeting Decision
We agree that this makes sense. Thanks!
We had some issues when copying activities containing checklist nodes across camps.
The checklist nodes have connections to checklist items. After copying such a checklist node to a new camp, the copy still has connections to the checklist items in the old camp. In the UI this does not display, because we only display checklist items from the current camp. But in the DB and API,
here are 48 such faulty connections on prod currently.
My proposed solution is to find replacement checklist items in the target camp. I thought about only matching the text of the item, but maybe there are courses with a checklist structure like:
So I opted for a little more advanced algorithm, matching the item text plus optionally the hierarchical parent items, plus the checklist name if all else matches.
To reproduce:
There are also some leftover Aufbau Checklist Prototypes which I now deactivated.